use std::{
	error::Error,
	fmt::Display,
	sync::{
		atomic::{AtomicU32, Ordering},
		Arc, RwLock,
	},
	thread,
	time::{Duration, UNIX_EPOCH},
};

use tokio::runtime::Runtime;

/// 获取自UNIX纪元以来的持续时间。
///
/// 该函数返回自1970年1月1日00:00:00 UTC以来的毫秒数。
/// 它使用`std::time::SystemTime`的`elapsed`方法来获取时间差，
/// 如果无法获取系统时间，则会抛出一个包含预期字符串的错误。
#[inline]
pub fn get_now_duration() -> Duration {
	UNIX_EPOCH.elapsed().expect("未能得到系统时间")
}

pub struct IDHelper;

#[derive(Debug)]
pub struct IdError {
	pub msg: &'static str,
}

impl Error for IdError {}
impl Display for IdError {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		write!(f, "IdHelper Error: {}", self.msg)
	}
}

struct IdData {
	last_time: i64,
	last_id: AtomicU32,
	work_id: i32,
}

impl IdData {
	fn next_id(&self) -> i64 {
		(self.last_time << 28)
			| (self.work_id << 18) as i64
			| (self.last_id.fetch_add(1, Ordering::Relaxed)) as i64
	}

	fn inner_add_time(&mut self) {
		let curr = get_now_duration().as_secs() as i64;

		//时间回拨的话，在这里一直等待，不过这样可能出现超长等待..或者使用pance?
		if curr < self.last_time {
			panic!("时间回拨了，当前时间小于系统时间")
		}

		if curr > self.last_time {
			self.last_time = curr;
			self.last_id.store(0, Ordering::Relaxed);
		}
	}
}

static mut IDS: Option<Arc<RwLock<IdData>>> = None;
fn load_ids() -> Arc<RwLock<IdData>> {
	unsafe {
		IDS
			.get_or_insert(Arc::new(RwLock::new(IdData {
				last_time: get_now_duration().as_secs() as i64,
				last_id: AtomicU32::new(0),
				work_id: 0,
			})))
			.clone()
	}
}

impl IDHelper {
		///使用协程初始化ID获取数据方式.
	pub fn init_coroutine(work_id: i32, runtime: &Runtime) {
		let one = unsafe {
			IDS
				.get_or_insert(Arc::new(RwLock::new(IdData {
					last_time: get_now_duration().as_secs() as i64,
					last_id: AtomicU32::new(0),
					work_id,
				})))
				.clone()
		};

		runtime.spawn(async move {
			loop {
				{
					let mut id_data = one.write().expect("协程获取id_data写入锁失败");
					id_data.inner_add_time();
				}

				let curr = 1000 - (get_now_duration().as_millis() % 1000) as u64;
				tokio::time::sleep(Duration::from_millis(curr)).await;
			}
		});
	}

	///使用线程初始化ID获取数据方式.将会产生一个独立线程用来调整时间
	pub fn init(work_id: i32) {
		let one = unsafe {
			IDS
				.get_or_insert(Arc::new(RwLock::new(IdData {
					last_time: get_now_duration().as_secs() as i64,
					last_id: AtomicU32::new(0),
					work_id,
				})))
				.clone()
		};

		thread::spawn(move || loop {
			{
				let mut id_data = one.write().expect("线程获取id_data写入锁失败");
				id_data.inner_add_time();
			}

			let curr = 1000 - (get_now_duration().as_millis() % 1000) as u64;
			thread::sleep(Duration::from_millis(curr))
		});
	}

	pub fn next_id(&self) -> i64 {
		let binding = load_ids();
		let id_data = binding.read().expect("获取id_data读锁失败");
		
		(*id_data).next_id()
	}
}


///生成输入值的md5码..字母是大写的
pub fn gen_md5_supp(source: &str) -> String {
	format!("{:X}", md5::compute(source))
}
